import os
import re
from typing import Dict, List, Any

def extract_code_segments(project_path: str, file_path: str) -> str:
    """
    提取特定文件的代码内容。
    
    如果 file_path 是相对路径，则基于 project_path 转换为绝对路径；
    如果 file_path 是绝对路径，则直接使用。
    """
    # 判断 file_path 是否为绝对路径
    if not os.path.isabs(file_path):
        # 如果是相对路径，将其转换为绝对路径
        full_path = os.path.join(project_path, file_path)
    else:
        # 如果是绝对路径，直接使用
        full_path = file_path

    # 检查文件是否存在
    if not os.path.exists(full_path):
        return f"File not found: {full_path}"
    
    # 读取文件内容
    with open(full_path, 'r', encoding='utf-8', errors='ignore') as f:
        return f.read()

def extract_function_code(project_path: str, file_path: str, function_name: str,class_name: str = None) -> str:
    """提取特定函数的代码"""

    """
    提取特定函数的代码。
    
    Args:
        project_path (str): 项目根目录路径。
        file_path (str): 目标文件路径。
        function_name (str): 要提取的函数名。
        class_name (str, optional): 类名（如果适用）。默认为 None。
    
    Returns:
        str: 提取的函数代码，或错误信息。
    """

    #function_name必须是class_name：：function_name
    code = extract_code_segments(project_path, file_path)
    
    lines = code.split('\n')
    if class_name:
              # 提取最内层的类名
        inner_class_name = class_name.split('::')[-1]
        full_function_name = f"{inner_class_name}::{function_name}"
    else:
        full_function_name = function_name

    # 带有返回类型的普通函数模式
    function_pattern = re.compile(rf'(def|void|int|char|double|float|bool|\w+)\s+{re.escape(full_function_name)}\s*\(')
    # 构造函数的模式
    constructor_pattern = re.compile(rf'{re.escape(full_function_name)}\s*\(')
    start_line = -1
    brace_count = 0
    in_function = False
    
    for i, line in enumerate(lines):
        if not in_function:
            if constructor_pattern.search(line) or function_pattern.search(line):
                start_line = i
                in_function = True
                if '{' in line:
                    brace_count += line.count('{')
                    brace_count -= line.count('}')
        else:
            if '{' in line:
                brace_count += line.count('{')
            if '}' in line:
                brace_count -= line.count('}')
            
            # Python函数通过缩进判断
            if line.strip() and not line.startswith(' ') and not line.startswith('\t'):
                if 'def ' in line or 'class ' in line:
                    return '\n'.join(lines[start_line:i])
            
            # C/C++通过花括号判断
            if brace_count == 0 and '{' in '\n'.join(lines[start_line:i]):
                return '\n'.join(lines[start_line:i+1])
    
    # 若没找到结束点，返回到文件末尾
    if start_line != -1:
        return '\n'.join(lines[start_line:])
    
    return f"Function {function_name} 未找到 {file_path}"

def extract_class_def_code(project_path: str, file_path: str, class_name: str) -> str:
    """提取特定类的代码"""
    code = extract_code_segments(project_path, file_path)
    
    lines = code.split('\n')
    class_pattern = re.compile(rf'(class|struct)\s+{re.escape(class_name)}')
    
    start_line = -1
    brace_count = 0
    in_class = False
    
    for i, line in enumerate(lines):
        if not in_class:
            if class_pattern.search(line):
                start_line = i
                in_class = True
                if '{' in line:
                    brace_count += line.count('{')
                    brace_count -= line.count('}')
        else:
            if '{' in line:
                brace_count += line.count('{')
            if '}' in line:
                brace_count -= line.count('}')
            
            # Python类通过缩进判断
            if line.strip() and not line.startswith(' ') and not line.startswith('\t'):
                if 'class ' in line:
                    return '\n'.join(lines[start_line:i])
            
            # C/C++类通过花括号判断
            if brace_count == 0 and '{' in '\n'.join(lines[start_line:i]):
                return '\n'.join(lines[start_line:i+1])
    
    # 若没找到结束点，返回到文件末尾
    if start_line != -1:
        return '\n'.join(lines[start_line:])
    
    return f"Class {class_name} 未找到 {file_path}"


def extract_class_code(project_path: str, file_path: str, class_name: str) -> str:
    """
    提取特定类的所有成员函数代码。
    
    Args:
        project_path (str): 项目根目录路径。
        file_path (str): 目标文件路径。
        class_name (str): 要提取的类名。
    
    Returns:
        str: 提取的类成员函数代码，或错误信息。
    """
    # 将文件路径转换为绝对路径
    file_path = os.path.abspath(os.path.join(project_path, file_path))
    
    # 检查文件是否存在
    if not os.path.exists(file_path):
        return f"文件未找到: {file_path}"
    
    # 提取代码段
    try:
        with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
            code = f.read()
    except Exception as e:
        return f"读取文件失败: {e}"
    
        # 提取最内层的类名
    class_name = class_name.split('::')[-1]
    
    # 定义正则表达式，匹配类成员函数定义
    member_function_pattern = re.compile(
        rf'{re.escape(class_name)}::(\w+)\s*\(',
        re.DOTALL
    )
    
    # 分割代码为段落（按空行分割）
    paragraphs = re.split(r'\n\s*\n', code)
    
    extracted_functions = []

    for paragraph in paragraphs:
        # 匹配类成员函数定义
        match = member_function_pattern.search(paragraph)
        if match:
            # 提取函数名
            function_name = match.group(1)
            full_function_name = f"{class_name}::{function_name}"
            print(f"Found member function: {full_function_name}")
            
            # 使用 extract_function_code 提取函数代码
            function_code = extract_function_code(project_path, file_path, function_name, class_name=class_name)
            if "未找到" not in function_code:
                extracted_functions.append(function_code)
    
    if extracted_functions:
        return "\n\n".join(extracted_functions)
    
    return f"类 {class_name} 的成员函数未找到于 {file_path}"


def convert_c_to_header(file_path):
    """
    将 C 文件路径转换为同名的头文件 (.h 或 .hpp) 路径。
    如果存在同名的 .h 文件，则优先使用 .h 文件；否则尝试 .hpp 文件。
    """
    # 获取文件所在目录和文件名（不含扩展名）
    dir_name, file_name = os.path.split(file_path)
    base_name, ext = os.path.splitext(file_name)
    
    # 构造可能的头文件路径
    h_file = os.path.join(dir_name, f"{base_name}.h")
    hpp_file = os.path.join(dir_name, f"{base_name}.hpp")
    
    # 检查是否存在对应的头文件
    if os.path.exists(h_file):
        return h_file
    elif os.path.exists(hpp_file):
        return hpp_file
    else:
        raise FileNotFoundError(f"未找到与 {file_path} 对应的头文件 (.h 或 .hpp){h_file}或{hpp_file}")


def extract_header(project_path: str, file_path: str) -> str:
    """提取特定类的代码"""

    """
    处理文件：将 C 文件路径转换为头文件路径，并提取代码段。
    """
    try:


        # 将文件路径转换为绝对路径
        file_path = os.path.abspath(os.path.join(project_path, file_path))
        # 将 C 文件路径转换为头文件路径
        header_file_path = convert_c_to_header(file_path)
        
        # 提取头文件中的代码段
        header = extract_code_segments(project_path, header_file_path)
        
        print(f"成功提取头文件内容: {header_file_path}")
        return header
    
    except FileNotFoundError as e:
        print(f"错误: {e}")
        return None
    

# 示例调用
if __name__ == "__main__":
    project_path = "/home/pnc/Documents/apollo/modules"
    file_path = "planning/planning_open_space/coarse_trajectory_generator/hybrid_a_star.cc"
    class_name = 'apollo::planning::HybridAStar'
    #function_name = 'HybridAStar'
    # function_name = 'AnalyticExpansion'   
    # function_name = 'ValidityCheck' 
    #function_name = 'LoadRSPinCS'
    #function_name = 'CalculateNodeCost'


    # result = extract_function_code(project_path, file_path, function_name,class_name)
    # print(result)

    extract_header = extract_header(project_path, file_path)
    #result = extract_class_code(project_path, file_path, class_name)
    print(extract_header)



